﻿using System.Data;

namespace Away.Admin.Repositories.Implements;

[ServiceInject(ServiceLifetime.Scoped)]
public class AdminRepository : SystemRepository, IAdminRepository
{
    public AdminRepository(SystemsDbContext context) : base(context)
    {
    }

    public bool AddAdmin(SysAdmin model)
    {
        Add(model);
        return Save();
    }

    public SysAdmin? GetAdminByUserName(string username)
    {
        return Query<SysAdmin>().FirstOrDefault(o => o.Username == username.Trim());
    }

    public ApiResult GetAdminPage(AdminSearch search)
    {
        var orgIds = Query<SysAdminOrganization>().AsNoTracking().Where(o => o.Mid == search.OrgId).Select(o => o.Oid);

        var cond = CondBuilder.New<SysAdmin>(true)
           .And(search.Id > 0, o => o.Id == search.Id)
           .And(!string.IsNullOrWhiteSpace(search.Nickname), o => o.Nickname.Contains(search.Nickname!))
           .And(!string.IsNullOrWhiteSpace(search.Username), o => o.Username.Contains(search.Username!))
           .And(!string.IsNullOrWhiteSpace(search.Realname), o => o.Realname.Contains(search.Realname!))
           .And(search.OrgId > 0, o => orgIds.Contains(o.Id));

        var tb = Query<SysAdmin>().Where(cond);

        var total = tb.Count();
        var items = tb.OrderByDescending(o => o.Id).Page(search).ToList();
        var adminIds = items.Select(o => o.Id).ToList();
        var orgList = Query<SysAdminOrganization>().AsNoTracking().Where(o => adminIds.Contains(o.Oid)).ToList();
        var roleList = Query<SysAdminRole>().AsNoTracking().Where(o => adminIds.Contains(o.Oid)).ToList();

        var roleIds = roleList.Select(o => o.Mid).ToList();
        var role_apiIds = Query<SysRoleApiResource>().AsNoTracking().Where(o => roleIds.Contains(o.Oid)).ToList();
        var admin_apiIds = Query<SysAdminApiResource>().AsNoTracking().Where(o => adminIds.Contains(o.Oid)).ToList();

        var role_viewIds = Query<SysRoleViewResource>().AsNoTracking().Where(o => roleIds.Contains(o.Oid)).ToList();
        var admin_viewIds = Query<SysAdminViewResource>().AsNoTracking().Where(o => adminIds.Contains(o.Oid)).ToList();


        var data = items.Select(admin =>
        {
            var orgs = orgList.Where(t => t.Oid == admin.Id).Select(o => o.Mid).ToArray();
            var roles = roleList.Where(t => t.Oid == admin.Id).Select(o => o.Mid).ToArray();

            var role_api_ids = role_apiIds.Where(o => roles.Contains(o.Oid)).Select(o => o.Mid).ToArray();
            var admin_api_ids = admin_apiIds.Where(o => o.Oid == admin.Id).Select(o => o.Mid).ToArray();
            var apis = new List<int>();
            apis.AddRange(role_api_ids);
            apis.AddRange(admin_api_ids);
            apis = apis.Distinct().ToList();

            var role_view_ids = role_viewIds.Where(o => roles.Contains(o.Oid)).Select(o => o.Mid).ToArray();
            var admin_view_ids = admin_viewIds.Where(o => o.Oid == admin.Id).Select(o => o.Mid).ToArray();
            var views = new List<int>();
            views.AddRange(role_view_ids);
            views.AddRange(admin_view_ids);
            views = views.Distinct().ToList();

            return new
            {
                admin.Desc,
                admin.CreateTime,
                admin.Avatar,
                admin.Realname,
                admin.Username,
                admin.Id,
                admin.Nickname,
                orgs,
                roles,
                apis,
                views
            };
        }).ToList();
        return ApiResult.Page(total, data);
    }

    public bool RemoveAdmin([Required] int[] ids)
    {
        var items = Query<SysAdmin>().Where(o => ids.Contains(o.Id)).ToArray();
        if (!items.Any())
        {
            return true;
        }
        Remove(items);
        return Save();
    }

    public bool SetApiResource(Permission model)
    {
        var items = Query<SysAdminApiResource>().Where(o => o.Oid == model.Oid).ToArray();
        var dels = items.Where(o => !model.Mid.Contains(o.Mid)).ToArray();
        if (dels.Any())
        {
            Remove(dels);
        }
        var adds = model.Mid
            .Where(o => !items.Any(t => t.Mid == o))
            .Select(o => new SysAdminApiResource { Mid = o, Oid = model.Oid })
            .ToArray();
        if (adds.Any())
        {
            Add(adds);
        }
        return Save();
    }

    public bool SetOrganization(Permission model)
    {
        var items = Query<SysAdminOrganization>().Where(o => o.Oid == model.Oid).ToList();
        var dels = items.Where(o => !model.Mid.Contains(o.Mid)).ToArray();
        if (dels.Any())
        {
            Remove(dels);
        }
        var adds = model.Mid
            .Where(o => !items.Any(t => t.Mid == o))
            .Select(o => new SysAdminOrganization { Mid = o, Oid = model.Oid })
            .ToArray();
        if (adds.Any())
        {
            Add(adds);
        }
        return Save();
    }

    public bool SetRoot(Permission model)
    {
        var items = Query<SysAdminRole>().Where(o => o.Oid == model.Oid).ToList();
        var dels = items.Where(o => !model.Mid.Contains(o.Mid)).ToArray();
        if (dels.Any())
        {
            Remove(dels);
        }
        var adds = model.Mid
            .Where(o => !items.Any(t => t.Mid == o))
            .Select(o => new SysAdminRole { Mid = o, Oid = model.Oid })
            .ToArray();
        if (adds.Any())
        {
            Add(adds);
        }
        return Save();
    }

    public bool SetViewResource(Permission model)
    {
        var items = Query<SysAdminViewResource>().Where(o => o.Oid == model.Oid).ToList();
        var dels = items.Where(o => !model.Mid.Contains(o.Mid)).ToArray();
        if (dels.Any())
        {
            Remove(dels);
        }
        var adds = model.Mid
            .Where(o => !items.Any(t => t.Mid == o))
            .Select(o => new SysAdminViewResource { Mid = o, Oid = model.Oid })
            .ToArray();
        if (adds.Any())
        {
            Add(adds);
        }
        return Save();
    }

    public bool UpdateAdmin(SysAdmin model)
    {
        Update(model);
        return Save();
    }

    public AdminInfo GetAdminInfo(int uid)
    {
        var admin = (from admin_tb in Query<SysAdmin>()
                     where admin_tb.Id == uid
                     select new AdminInfo
                     {
                         UserId = admin_tb.Id,
                         Username = admin_tb.Username,
                         Realname = admin_tb.Realname,
                         Avatar = admin_tb.Avatar,
                         Desc = admin_tb.Desc
                     }).FirstOrDefault();

        var org = (from org_tb in Query<SysOrganization>()
                   join admin_org in Query<SysAdminOrganization>().Where(o => o.Oid == uid) on org_tb.Id equals admin_org.Mid into ao
                   from admin_org in ao.DefaultIfEmpty()
                   where admin_org != null
                   select org_tb.DeptName).ToList();

        var root = (from root_tb in Query<SysRole>()
                    join admin_root in Query<SysAdminRole>().Where(o => o.Oid == uid) on root_tb.Id equals admin_root.Mid into ar
                    from admin_root in ar.DefaultIfEmpty()
                    where admin_root != null
                    select new RootInfo
                    {
                        RoleName = root_tb.RoleName,
                        RoleValue = root_tb.RoleValue
                    }).ToList();

        if (admin != null)
        {
            admin.Orgs = org;
            admin.Roots = root;
        }
        return admin ?? new AdminInfo();
    }

    public bool HasApiPerm(ApiPermSearch search)
    {
        var roleIds = (from role in Query<SysRole>()
                       join admin_role in Query<SysAdminRole>() on role.Id equals admin_role.Mid
                       where admin_role.Oid == search.AdminId
                       select role.Id).ToArray();

        var role_apiIds = Query<SysRoleApiResource>().Where(o => roleIds.Contains(o.Oid)).Select(o => o.Mid).ToArray();
        var admin_apiIds = Query<SysAdminApiResource>().Where(o => o.Oid == search.AdminId).Select(o => o.Mid).ToArray();

        var apiIds = new List<int>();
        apiIds.AddRange(role_apiIds);
        apiIds.AddRange(admin_apiIds);
        apiIds = apiIds.Distinct().ToList();

        var api = from api_tb in Query<SysApiResource>()
                  where apiIds.Contains(api_tb.Id) && api_tb.Url == search.Url && api_tb.Method == search.Method
                  select api_tb.Id;
        return api.Any();
    }

    public List<string> GetViewPermCode(int uid)
    {
        var ids = Query<SysAdminViewResource>()
            .AsNoTracking()
            .Where(o => o.Oid == uid && o.Mid < 0)
            .Select(o => 0 - o.Mid)
            .ToList();

        var roleIds = Query<SysAdminRole>()
            .AsNoTracking()
            .Where(o => o.Oid == uid)
            .Select(o => o.Mid)
            .ToArray();

        if (roleIds.Any())
        {
            var role_view_ids = Query<SysRoleViewResource>()
                .AsNoTracking()
                .Where(o => roleIds.Contains(o.Oid) && o.Mid < 0)
                .Select(o => 0 - o.Mid)
                .ToList();
            ids.AddRange(role_view_ids);
        }
        return Query<SysViewResourcePrem>()
            .AsNoTracking()
            .Where(o => ids.Contains(o.Id))
            .Select(o => o.PremCode)
            .ToList();
    }

    public List<SysViewResource> GetViews(int uid)
    {
        var roleIds = (from role in Query<SysRole>().AsNoTracking()
                       join admin_role in Query<SysAdminRole>().AsNoTracking() on role.Id equals admin_role.Mid
                       where admin_role.Oid == uid
                       select role.Id).ToArray();

        var role_viewIds = Query<SysRoleViewResource>().AsNoTracking().Where(o => roleIds.Contains(o.Oid)).Select(o => o.Mid).ToArray();
        var admin_viewIds = Query<SysAdminViewResource>().AsNoTracking().Where(o => o.Oid == uid).Select(o => o.Mid).ToArray();

        var viewIds = new List<int>();
        viewIds.AddRange(role_viewIds);
        viewIds.AddRange(admin_viewIds);
        viewIds = viewIds.Distinct().ToList();

        return Query<SysViewResource>().AsNoTracking().Where(o => o.Status == 0).Where(o => viewIds.Contains(o.Id)).ToList();
    }
}
